package top.frsf.rpc.autoconfigure.proxy;

import cn.hutool.json.JSONObject;
import io.netty.channel.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import top.frsf.rpc.annotations.RpcReference;
import top.frsf.rpc.entity.ServiceInstance;
import top.frsf.rpc.factory.LoadBalanceFactory;
import top.frsf.rpc.handler.RpcResponseHandler;
import top.frsf.rpc.loadbalance.LoadBalance;
import top.frsf.rpc.protocol.RpcMessage;
import top.frsf.rpc.protocol.body.RpcReqBody;
import top.frsf.rpc.protocol.body.RpcRespBody;
import top.frsf.rpc.protocol.head.RpcHeader;
import top.frsf.rpc.registry.ServiceRegistry;
import top.frsf.rpc.session.ClientSessionManager;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * RPC代理类 Handler
 *
 * @author He Kuntao
 * @since 2025/7/8 10:21
 */
@Slf4j
@RequiredArgsConstructor
public class RpcInvocationHandler implements InvocationHandler {

    private final Class<?> interfaceClass;

    private final RpcReference rpcReference;

    private final ServiceRegistry serviceRegistry;

    private final ClientSessionManager sessionManager;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 跳过Object类的方法
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }

        // 获取注册中心服务列表
        List<ServiceInstance> instances = serviceRegistry.discover(interfaceClass.getName());
        if (instances == null || instances.isEmpty()) {
            throw new RuntimeException("No service instance found for " + interfaceClass.getName());
        }

        // 获取LoadBalance
        LoadBalance loadBalance = LoadBalanceFactory.getLoadBalance(rpcReference.loadBalance());
        log.info("Using load balance strategy: {}", loadBalance.getLoadBalanceEnum());
        ServiceInstance instance = loadBalance.select(instances);
        log.info("Selected service instance: {}", instance);

        // 获取Channel
        Channel channel = sessionManager.getOrCreateChannel(instance);

        // 构造RPC请求
        RpcReqBody body = RpcReqBody.builder()
                .serviceInterface(interfaceClass)
                .methodName(method.getName())
                .parameters(args)
                .parameterTypes(method.getParameterTypes())
                .build();
        RpcMessage<RpcReqBody> message = RpcMessage.builderReqMsg(body);

        // 注册回调
        RpcHeader header = message.getHeader();
        CompletableFuture<RpcRespBody> completableFuture = RpcResponseHandler.registerPendingRequest(header.getRequestId());

        // 发送消息
        channel.writeAndFlush(message);

        // 等待响应
        try {
            RpcRespBody rpcRespBody = completableFuture.get(5, TimeUnit.SECONDS);
            log.info("Received response: {}", rpcRespBody);
            Object result = rpcRespBody.getResult();
            if (result instanceof JSONObject) {
                return ((JSONObject)result).toBean(method.getReturnType());
            }
            return result;
        } catch (TimeoutException e) {
            completableFuture.cancel(true);
            throw new RuntimeException(e);
        }
    }
}
